﻿using Catalogo.Portable.Helpers;
using Catalogo.Portable.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Catalogo.Portable.DataSources
{
    public abstract class CatalogoDataSource
    {
        protected const string APPLICATION_URL = "https://[sua conta].azure-mobile.net/";
        protected const string APPLICATION_KEY = "[sua chave]";

        private static CatalogoDataSource _Instance;
        public static CatalogoDataSource Instance
        {
            get
            {
                if (_Instance == null)
                {
                    _Instance = AssemblyHelper.CreateSpecificInstanceOf<CatalogoDataSource>();
                }
                return _Instance;
            }
        }

        private Dictionary<string, Item> _Itens;
        private Empresa _Empresa;
        private Dictionary<string, Categoria> _Categorias;

        public async Task<List<Categoria>> ObterCategoriasComItensAsync(int? maxItensPorCategoria = null)
        {
            await LoadAsync();

            return (from categoria in _Categorias.Values
                    select new Categoria()
                            {
                                Descricao = categoria.Descricao,
                                Id = categoria.Id,
                                ImageUrl = categoria.ImageUrl,
                                Itens = new ObservableCollection<Item>(categoria.Itens.Take(maxItensPorCategoria.GetValueOrDefault(int.MaxValue))),
                                Nome = categoria.Nome,
                                SubTitulo = categoria.SubTitulo,
                            }
                    ).ToList();
        }

        public async Task<List<Categoria>> BuscarCategoriasComItensAsync(string busca)
        {
            await LoadAsync();

            var resultado = new List<Categoria>();
            foreach (var categoria in _Categorias.Values)
            {
                Categoria searchCategory = null;
                bool founded;

                foreach (Item item in categoria.Itens)
                {
                    founded = false;

                    if (item.Nome.IndexOf(busca, StringComparison.CurrentCultureIgnoreCase) > -1
                        || item.Descricao.IndexOf(busca, StringComparison.CurrentCultureIgnoreCase) > -1
                        || item.SubTitulo.IndexOf(busca, StringComparison.CurrentCultureIgnoreCase) > -1
                        || item.Categoria.Descricao.IndexOf(busca, StringComparison.CurrentCultureIgnoreCase) > -1
                        || item.SubTitulo.IndexOf(busca, StringComparison.CurrentCultureIgnoreCase) > -1
                        || item.Categoria.Nome.IndexOf(busca, StringComparison.CurrentCultureIgnoreCase) > -1
                    )
                    {
                        founded = true;
                    }

                    if (founded)
                    {
                        if (searchCategory == null)
                        {
                            searchCategory = new Categoria()
                            {
                                Descricao = categoria.Descricao,
                                Id = categoria.Id,
                                ImageUrl = categoria.ImageUrl,
                                Itens = new ObservableCollection<Item>(),
                                Nome = categoria.Nome,
                                SubTitulo = categoria.SubTitulo,
                            };
                        }
                        searchCategory.Itens.Add(item);
                    }

                }

                if (searchCategory != null)
                {
                    resultado.Add(searchCategory);
                }
            }
            return resultado;
        }

        public async Task LoadAsync()
        {
            if (_Categorias == null)
            {
                var categorias = await InternalObterTodasCategoriasAsync();
                _Categorias = categorias.ToDictionary((c) => c.Id);

                var itens = await InternalObterTodosItensAsync();

                foreach (var item in itens)
                {
                    if (_Categorias.ContainsKey(item.IdCategoria))
                    {
                        var categoria = _Categorias[item.IdCategoria];
                        item.Categoria = categoria;
                        categoria.Itens.Add(item);
                    }
                }

                _Itens = categorias.SelectMany((c) => c.Itens).ToDictionary((i) => i.Id);
            }
        }

        public async Task<Empresa> ObterEmpresaAsync()
        {
            if (_Empresa == null)
            {
                _Empresa = await InternalObterEmpresaAsync();
            }
            return _Empresa;
        }

        public async Task<Item> ObterItemAsync(string idItem)
        {
            await LoadAsync();
            if (_Itens.ContainsKey(idItem))
            {
                return _Itens[idItem];
            }
            return null;
        }

        public async Task<Categoria> ObterCategoriaAsync(string idCategoria)
        {
            await LoadAsync();
            if (_Categorias.ContainsKey(idCategoria))
            {
                return _Categorias[idCategoria];
            }
            return null;
        }

        public async Task InserirCategoriaAsync(Categoria categoria)
        {
            await InternalInserirCategoriaAsync(categoria);
        }

        public async Task InserirItemAsync(Item item)
        {
            await InternalInserirItemAsync(item);
        }

        public async Task InserirEmpresaAsync(Empresa empresa)
        {
            await InternalInserirEmpresaAsync(empresa);
        }

        protected abstract Task<List<Categoria>> InternalObterTodasCategoriasAsync();
        protected abstract Task<List<Item>> InternalObterTodosItensAsync();
        protected abstract Task<Empresa> InternalObterEmpresaAsync();
        protected abstract Task InternalInserirCategoriaAsync(Categoria categoria);
        protected abstract Task InternalInserirItemAsync(Item item);
        protected abstract Task InternalInserirEmpresaAsync(Empresa empresa);
    }
}
